﻿using System;
using System.Collections.Generic;
using Runtime.Models;
using Runtime.Services.Battle;
using Runtime.Services.Battle.Entity;
using Runtime.Services.BattleAttack;

namespace Runtime.Services.BattleSkill {

    /// <summary>
    /// 战斗技能攻击者
    /// </summary>
    public interface IDFR_BattleSkillAttacker : IDFR_BattleAttacker {

        IDFR_BattleAttackBulletProvider AsBulletProvider();

        IDFR_BattleAttackBulletSetter AsBulletSetter();

        /// <summary>
        /// 效果实例ID
        /// </summary>
        public DFR_BattleEntityInstanceID EffectEntityInstanceID { get; }

        /// <summary>
        /// 是否取消普通攻击
        /// </summary>
        bool IsCancelNormalAttack { get; }

        /// <summary>
        /// 是否使用原始进攻者数据
        /// </summary>
        bool UseOriginAttacker { get; }

        /// <summary>
        /// Debuff效果数据
        /// </summary>
        IDFR_BattleEffectModelBase DebuffEffectModel { get; }

        /// <summary>
        /// 击杀目标数据集
        /// </summary>
        IReadOnlyDictionary<DFR_BattleEntityInstanceID, IDFR_BattleAttackTarget> KillTargetDictionary { get; }
    }

    public abstract partial class DFR_BattleSkillServiceBase {

        protected sealed class Attacker : DFR_Entity, IDFR_BattleSkillAttacker, IDFR_BattleAttackBulletProvider, IDFR_BattleAttackBulletSetter {

            public IDFR_BattleAttackBulletProvider AsBulletProvider() => this;

            public IDFR_BattleAttackBulletSetter AsBulletSetter() => this;

            public DFR_BattleEntityInstanceID EntityInstanceID { get; private init; }

            public DFR_BattleEntityInstanceID EffectEntityInstanceID { get; private init; }

            public DFR_BattleMapPosition MapPosition { get; private set; }

            public DFR_BattleAttackHit AttackHit { get; private init; }

            public IReadOnlyDictionary<DFR_BattleEntityInstanceID, IDFR_BattleAttackTarget> KillTargetDictionary { get; private set; }

            public Attacker(IDFR_BattleAttacker attacker, IDFR_BattleEffectModelBase effectModel, IDFR_BattleSkillModelBase skillModel, IReadOnlyDictionary<DFR_BattleEntityInstanceID, IDFR_BattleAttackTarget> killTargetDictionary, bool useOriginAttacker) : base() {
                EntityInstanceID = attacker.EntityInstanceID;
                EffectEntityInstanceID = new() { ID = effectModel.EntityInstanceID.ID };
                BattleSkillServiceBase.Instance.AddEffectModel(EffectEntityInstanceID, effectModel);
                MapPosition = attacker.MapPosition;
                AttackHit = attacker.AttackHit;
                KillTargetDictionary = killTargetDictionary;
                UseOriginAttacker = useOriginAttacker;

                Initialize();

                if (effectModel.IsAttacking || UseOriginAttacker) {
                    m_OriginAttackSpeed = attacker.AttackSpeedFinalFactor == F64.Zero ? F64.Zero : attacker.AttackSpeed.Value / attacker.AttackSpeedFinalFactor;
                    m_AttackSpeed.Base.Add(attacker.AttackSpeed);
                }

                ApplyEffect(effectModel);
                ApplyBullet(effectModel, skillModel);
            }

            private F64 m_OriginAttackSpeed;
            public F64 AttackSpeedFinalFactor => m_OriginAttackSpeed == F64.Zero ? F64.Zero : m_AttackSpeed.Value / m_OriginAttackSpeed;

            /// <summary>
            /// 不应对技能查询攻击发起总数
            /// </summary>
            public IReadOnlyIntData LaunchCount => throw new InvalidProgramException();

            public bool IsCancelNormalAttack { get; init; }

            public bool UseOriginAttacker { get; private set; }

            public IDFR_BattleEffectModelBase DebuffEffectModel { get; set; }

            [Autowired]
            private readonly IDFR_BattleComplexData m_DamageHPMax;
            public IDFR_ReadOnlyBattleData DamageHPMax => m_DamageHPMax;

            [Autowired]
            private readonly IDFR_BattleComplexData m_DamageHP;
            public IDFR_ReadOnlyBattleData DamageHP => m_DamageHP;

            [Autowired]
            private readonly IDFR_BattleComplexData m_Damage;
            public IDFR_ReadOnlyBattleData Damage => m_Damage;

            [Autowired]
            private readonly IDFR_BattleComplexData m_Attack;
            public IDFR_ReadOnlyBattleData Attack => m_Attack;

            [Autowired]
            private readonly IDFR_BattleComplexData m_AttackBossAdditional;
            public IDFR_ReadOnlyBattleData AttackBossAdditional => m_AttackBossAdditional;

            [Autowired]
            private readonly IDFR_BattleComplexData m_AttackSpeed;
            public IDFR_ReadOnlyBattleData AttackSpeed => m_AttackSpeed;

            [Autowired]
            private readonly IDFR_BattleComplexData m_Critical;
            public IDFR_ReadOnlyBattleData Critical => m_Critical;

            [Autowired]
            private readonly IDFR_BattleComplexData m_CriticalPower;
            public IDFR_ReadOnlyBattleData CriticalPower => m_CriticalPower;

            private string m_BulletFlyAssetKey;
            string IDFR_BattleAttackBulletProvider.BulletFlyAssetKey => m_BulletFlyAssetKey;

            private string m_BulletHitAssetKey;
            string IDFR_BattleAttackBulletProvider.BulletHitAssetKey => m_BulletHitAssetKey;

            private F64 m_BulletFlySpeed;
            F64 IDFR_BattleAttackBulletProvider.BulletFlySpeed => m_BulletFlySpeed;

            void IDFR_BattleAttackBulletSetter.SetBulletFlySpeed(F64 value) => m_BulletFlySpeed = value;

            void IDFR_BattleAttackBulletSetter.SetBulletAssetKey(string fly, string hit) {
                m_BulletFlyAssetKey = fly;
                m_BulletHitAssetKey = hit;
            }

            private void Initialize() {
                m_DamageHPMax.Initialize(F64.Zero, F64.One, F64.Zero);
                m_DamageHP.Initialize(F64.Zero, F64.One, F64.Zero);
                m_Damage.Initialize(F64.Zero, F64.One, F64.Zero);
                m_Attack.Initialize(F64.Zero, F64.One, F64.Zero);
                m_AttackBossAdditional.Initialize(F64.Zero, F64.One, F64.Zero);
                m_AttackSpeed.Initialize(F64.Zero, F64.One, F64.Zero);
                m_Critical.Initialize(F64.Zero, F64.One, F64.Zero);
                m_CriticalPower.Initialize(F64.Zero, F64.One, F64.Zero);
            }

            private void ApplyBullet(IDFR_BattleEffectModelBase effectModel, IDFR_BattleSkillModelBase skillModel) {
                m_BulletFlyAssetKey = skillModel.BulletAssetKey;
                m_BulletHitAssetKey = effectModel.ModelAssetKey;
            }

            private void ApplyEffect(IDFR_BattleEffectModelBase effectModel) {
                var source = effectModel.AsBuffProvider();
                if (source.DamageHPMaxBase != null) {
                    m_DamageHPMax.Base.Add(source.DamageHPMaxBase);
                } else if (source.DamageHPMaxFactor != null) {
                    m_DamageHPMax.Factor.Add(source.DamageHPMaxFactor);
                } else if (source.DamageHPMaxAdditional != null) {
                    m_DamageHPMax.Additional.Add(source.DamageHPMaxAdditional);
                } else if (source.DamageHPBase != null) {
                    m_DamageHP.Base.Add(source.DamageHPBase);
                } else if (source.DamageHPFactor != null) {
                    m_DamageHP.Factor.Add(source.DamageHPFactor);
                } else if (source.DamageHPAdditional != null) {
                    m_DamageHP.Additional.Add(source.DamageHPAdditional);
                } else if (source.DamageBase != null) {
                    m_Damage.Base.Add(source.DamageBase);
                } else if (source.DamageFactor != null) {
                    m_Damage.Factor.Add(source.DamageFactor);
                } else if (source.DamageAdditional != null) {
                    m_Damage.Additional.Add(source.DamageAdditional);
                } else if (source.AttackBase != null) {
                    m_Attack.Base.Add(source.AttackBase);
                } else if (source.AttackFactor != null) {
                    m_Attack.Factor.Add(source.AttackFactor);
                } else if (source.AttackAdditional != null) {
                    m_Attack.Additional.Add(source.AttackAdditional);
                } else if (source.AttackBossAdditionalBase != null) {
                    m_AttackBossAdditional.Base.Add(source.AttackBossAdditionalBase);
                } else if (source.AttackBossAdditionalFactor != null) {
                    m_AttackBossAdditional.Factor.Add(source.AttackBossAdditionalFactor);
                } else if (source.AttackBossAdditionalAdditional != null) {
                    m_AttackBossAdditional.Additional.Add(source.AttackBossAdditionalAdditional);
                } else if (source.AttackSpeedBase != null) {
                    m_AttackSpeed.Base.Add(source.AttackSpeedBase);
                } else if (source.AttackSpeedFactor != null) {
                    m_AttackSpeed.Factor.Add(source.AttackSpeedFactor);
                } else if (source.AttackSpeedAdditional != null) {
                    m_AttackSpeed.Additional.Add(source.AttackSpeedAdditional);
                } else if (source.CriticalBase != null) {
                    m_Critical.Base.Add(source.CriticalBase);
                } else if (source.CriticalFactor != null) {
                    m_Critical.Factor.Add(source.CriticalFactor);
                } else if (source.CriticalAdditional != null) {
                    m_Critical.Additional.Add(source.CriticalAdditional);
                } else if (source.CriticalPowerBase != null) {
                    m_CriticalPower.Base.Add(source.CriticalPowerBase);
                } else if (source.CriticalPowerFactor != null) {
                    m_CriticalPower.Factor.Add(source.CriticalPowerFactor);
                } else if (source.CriticalPowerAdditional != null) {
                    m_CriticalPower.Additional.Add(source.CriticalPowerAdditional);
                }
            }

            protected override void Dispose() {
                BattleSkillServiceBase.Instance.RemoveEffectModel(EffectEntityInstanceID);
                KillTargetDictionary = null;
                DebuffEffectModel = null;
                base.Dispose();
            }
        }
    }
}